const WEBGL = require('../lib/WebGL');
const Viewer = require('./viewer');
const SimpleDropzone = require('simple-dropzone');
const ValidationController = require('./validation-controller');
const queryString = require('query-string');

if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
    console.error('The File APIs are not fully supported in this browser.');
} else if (!WEBGL.isWebGLAvailable()) {
    console.error('WebGL is not supported in this browser.');
}

class App {

    /**
     * @param  {Element} el
     * @param  {Location} location
     */
    constructor(el, location) {

        const hash = location.hash ? queryString.parse(location.hash) : {};
        this.options = {
            kiosk: Boolean(hash.kiosk),
            model: hash.model || '',
            preset: hash.preset || '',
            cameraPosition: hash.cameraPosition
                ? hash.cameraPosition.split(',').map(Number)
                : null
        };

        this.el = el;
        this.viewer = null;
        this.viewerEl = null;
        this.spinnerEl = el.querySelector('.spinner');
        this.dropEl = el.querySelector('.dropzone');
        this.inputEl = el.querySelector('#file-input');
        this.validationCtrl = new ValidationController(el);

        this.createDropzone();
        this.hideSpinner();

        const options = this.options;

        if (options.kiosk) {
            const headerEl = document.querySelector('header');
            headerEl.style.display = 'none';
        }

        if (options.model) {
            this.view(options.model, '', new Map());
        }

        //加载后运行
        this.loadByPath();
    }

    /**
     * 读取链接参数进行模型的加载hm
     */
    loadByPath() {
        // var file = "192.168.30.28:8100/14699.gltf";
        var scope = this;
        var getQueryString = function (name) {
            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
            var r = window.location.search.substr(1).match(reg);
            if (r != null) return unescape(r[2]);
            return null;
        };
        var downLoadFile = function (url) {
            let xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = 'arraybuffer';

            xhr.onload = (e) => {
                let file = new File([xhr.response], url);
                let map = new Map();
                map.set(url, file);
                let mtl = getQueryString("mtl");
                if (mtl) {
                    scope.loadObjMtl(mtl, function (result) {
                        file.materials = result;
                        scope.load(map);
                    })
                } else {
                    scope.load(map);
                }
            };
            xhr.send();
        };

        let url = getQueryString("url");
        url && downLoadFile(url);
    }

    loadObjMtl(url, call) {
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'arraybuffer';

        xhr.onload = (e) => {
            // let file = new File([xhr.response], url);
            let mtlLoader = new THREE.MTLLoader();
            // let file = new File([xhr.response], url);
            // const fileUrl = typeof file === 'string'
            //     ? file : URL.createObjectURL(file);
            //
            // URL.revokeObjectURL(fileUrl);

            mtlLoader.load(url, (result) => {
                call && call(result)
            })
        };
        xhr.send();
    }

    /**
     * Sets up the drag-and-drop controller.
     */
    createDropzone() {
        const dropCtrl = new SimpleDropzone(this.dropEl, this.inputEl);
        dropCtrl.on('drop', ({files}) => this.load(files));
        dropCtrl.on('dropstart', () => this.showSpinner());
        dropCtrl.on('droperror', () => this.hideSpinner());
    }

    /**
     * Sets up the view manager.
     * @return {Viewer}
     */
    createViewer() {
        this.viewerEl = document.createElement('div');
        this.viewerEl.classList.add('viewer');
        this.dropEl.innerHTML = '';
        this.dropEl.appendChild(this.viewerEl);
        this.viewer = new Viewer(this.viewerEl, this.options);
        return this.viewer;
    }

    /**
     * Loads a fileset provided by user action.
     * @param  {Map<string, File>} fileMap
     */
    load(fileMap) {
        let rootFile;
        let rootPath;
        let fileExt;
        Array.from(fileMap).forEach(([path, file]) => {
            if (file.name.toLowerCase().match(/\.(gltf|glb|b3dm|fbx|obj|ogl)$/)) {
                rootFile = file;
                rootPath = path.replace(file.name, '');
                fileExt = file.name.substring(file.name.lastIndexOf(".") + 1, file.name.length);
            }
        });

        if (!rootFile) {
            this.onError('No .gltf or .glb or .b3dm or .FBX or .obj asset found.');
        }

        this.view(rootFile, rootPath, fileMap, fileExt);
    }

    /**
     * Passes a model to the viewer, given file and resources.
     * @param  {File|string} rootFile
     * @param  {string} rootPath
     * @param  {Map<string, File>} fileMap
     */
    view(rootFile, rootPath, fileMap, fileExt) {

        if (this.viewer) this.viewer.clear();

        const viewer = this.viewer || this.createViewer();

        const fileURL = typeof rootFile === 'string'
            ? rootFile
            : URL.createObjectURL(rootFile);

        const cleanup = () => {
            this.hideSpinner();
            if (typeof rootFile === 'object') URL.revokeObjectURL(fileURL);
        };

        viewer
            .load(fileURL, rootPath, fileMap, fileExt)
            .catch((e) => this.onError(e))
            .then((gltf) => {
                if (!this.options.kiosk) {
                    this.validationCtrl.validate(fileURL, rootPath, fileMap, gltf);
                }
                console.log(viewer)
                cleanup();
            });
    }

    /**
     * @param  {Error} error
     */
    onError(error) {
        let message = (error || {}).message || error.toString();
        if (message.match(/ProgressEvent/)) {
            message = 'Unable to retrieve this file. Check JS console and browser network tab.';
        } else if (message.match(/Unexpected token/)) {
            message = `Unable to parse file content. Verify that this file is valid. Error: "${message}"`;
        } else if (error && error.target && error.target instanceof Image) {
            error = 'Missing texture: ' + error.target.src.split('/').pop();
        }
        window.alert(message);
        console.error(error);
    }

    showSpinner() {
        this.spinnerEl.style.display = '';
    }

    hideSpinner() {
        this.spinnerEl.style.display = 'none';
    }
}

document.addEventListener('DOMContentLoaded', () => {

    const app = new App(document.body, location);

    const exportObjButton = document.getElementById('exportObj');
    exportObjButton.addEventListener('click', function () {
        app.viewer.objExport();
    });

    const exportGlbButton = document.getElementById('exportGlb');
    exportGlbButton.addEventListener('click', function () {
        app.viewer.glbExport();
    });
});

